﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Assist;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Electrical;
using Autodesk.Revit.DB.Mechanical;
using Autodesk.Revit.DB.Plumbing;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
using YArchitech.ProgressBar;
using HYOpeningCommon.DbOpening;
using HYOpeningCommon.Public;
using HYOpeningDesignInput.ConfigForm;
using HYOpeningDesignInput.DbOpeningCreatorFactory;
using HYOpeningDesignInput.EquipCollector;
using HYOpeningDesignInput.Public;

namespace HYOpeningDesignInput.Cmd
{
	[Transaction(TransactionMode.Manual)]
	[Regeneration(RegenerationOption.Manual)]
	public class CmdOpeningDesignInput : IExternalCommand
	{
		[DllImport("user32.dll", EntryPoint = "SendMessageA")]
		public static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);

		public Result Execute(ExternalCommandData cmdData, ref string messages, ElementSet elements)
		{
			if (cmdData.Application.ActiveUIDocument.Document.IsModified)
			{
				MessageBox.Show("请先保存项目。");
				return Autodesk.Revit.UI.Result.Cancelled;
			}
			MEPData mepdata = new MEPData();
			LinkedList<DbOpeningBase> lstDbOpening = new LinkedList<DbOpeningBase>();
			UIDocument activeUIDocument = cmdData.Application.ActiveUIDocument;
			Document document = activeUIDocument.Document;
			List<Document> list = new List<Document>();
			list.Add(document);
			IEnumerable<Document> enumerable = CommonInterface.GetLinkDocs(document).Distinct<Document>();
			if (enumerable != null && enumerable.Count<Document>() != 0)
			{
				list.AddRange(enumerable);
			}
			if (!this.GetAllMEPCurve(list, ref mepdata))
			{
				return Autodesk.Revit.UI.Result.Succeeded;
			}
			new EquipMentCollector(document).GetEquips(ref mepdata);
			new List<Grid>();
			if (!GridData.GetGridInfos(list, ref mepdata.m_lstInfos))
			{
				return Autodesk.Revit.UI.Result.Succeeded;
			}
			IntPtr mainWindowHandle = Process.GetCurrentProcess().MainWindowHandle;
			this._hWndRevit = new WindowHandle(mainWindowHandle);
			if (!this.GetAllOpeningData(list, ref lstDbOpening, mepdata))
			{
				return Autodesk.Revit.UI.Result.Succeeded;
			}
			GraphicsStyle graphicsStyle = null;
			CommonInterface.GetPreViewStyle(ref graphicsStyle, document);
			if (graphicsStyle == null)
			{
				return Autodesk.Revit.UI.Result.Succeeded;
			}
			PreViewScene preViewScene = new PreViewScene(document, graphicsStyle.Id, 0.32808398950131235);
			Autodesk.Revit.DB.View activeView = document.ActiveView;
			using (TransactionGroup transactionGroup = new TransactionGroup(document))
			{
				try
				{
					transactionGroup.Start("TransGroupCreateModelGroup");
					if (!this.CreatePreviewIns(ref lstDbOpening, document, preViewScene))
					{
						return Autodesk.Revit.UI.Result.Succeeded;
					}
					this.OpeningDesignInputFormShow(lstDbOpening, cmdData);
				}
				catch (Exception ex)
				{
                    if ((int)transactionGroup.GetStatus() == 1)
					{
						transactionGroup.RollBack();
					}
					if (document.ActiveView.Id != activeView.Id)
					{
						activeUIDocument.ActiveView = activeView;
					}
					ExceptionLog.WriteLog(ex.Message, true);
					throw;
				}
				finally
				{
					if (transactionGroup.HasStarted())
					{
						transactionGroup.RollBack();
					}
					if (document.ActiveView.Id != activeView.Id)
					{
						activeUIDocument.ActiveView = activeView;
					}
					ExceptionLog.CloseLogFile();
				}
			}
			return Autodesk.Revit.UI.Result.Succeeded;
		}

		private bool CreatePreviewIns(ref LinkedList<DbOpeningBase> lstDbOpening, Autodesk.Revit.DB.Document doc, PreViewScene preViewScene)
		{
			ProgressBarForm progressBarForm = new ProgressBarForm(lstDbOpening.Count, ProgressBarStyle.Blocks, true);
			bool result;
			try
			{
				progressBarForm.Text = "创建洞口预览";
				progressBarForm.ShowInTaskbar = false;
				progressBarForm.Show(this._hWndRevit);
				foreach (DbOpeningBase dbOpeningBase in lstDbOpening)
				{
					Element element = null;
					dbOpeningBase.CreateOpeningPreviewInstance(out element, preViewScene);
					if (element != null)
					{
						dbOpeningBase.m_idModelGroup = element.Id;
					}
					progressBarForm.RefreshProgressBar();
					if (progressBarForm.m_stopTag)
					{
						return false;
					}
				}
				progressBarForm.Dispose();
				result = true;
			}
			catch (Exception)
			{
				progressBarForm.Dispose();
				throw;
			}
			return result;
		}

		private void OpeningDesignInputFormShow(LinkedList<DbOpeningBase> lstDbOpening, ExternalCommandData cmdData)
		{
			UIDocument activeUIDocument = cmdData.Application.ActiveUIDocument;
			Document document = activeUIDocument.Document;
			CommonInterface.SetView3DChanged(activeUIDocument);
			OpeningDesignInputReportForm openingDesignInputReportForm = new OpeningDesignInputReportForm(lstDbOpening, cmdData, this._hWndRevit);
			openingDesignInputReportForm.SetOpeningData2DataGridView();
			openingDesignInputReportForm.Show(this._hWndRevit);
			int wMsg = 7;
			CmdOpeningDesignInput.SendMessage(this._hWndRevit.Handle, wMsg, IntPtr.Zero, IntPtr.Zero);
			Selection selection = activeUIDocument.Selection;
			for (;;)
			{
				try
				{
					selection.PickElementsByRectangle("");
					List<Element> selElements = new List<Element>();
					RevitVersionFuncs.SetSelection(activeUIDocument.Selection, selElements);
					activeUIDocument.RefreshActiveView();
					continue;
				}
				catch (Exception)
				{
				}
				break;
			}
			openingDesignInputReportForm.Close();
		}

		private bool GetAllOpeningData(List<Document> lstDoc, ref LinkedList<DbOpeningBase> lstDbOpening, MEPData m_mepData)
		{
			Dictionary<string, int> dictionary = new Dictionary<string, int>();
			Interface.GetXmlData(ref dictionary);
			bool result;
			try
			{
				if (!new DbWallStraightOpeningCreateFactory(ref lstDoc, this._hWndRevit, dictionary).CreateDbOpening(m_mepData, ref lstDbOpening))
				{
					result = false;
				}
				else if (!new DbFloorOpeningCreatorFactory(ref lstDoc, this._hWndRevit, dictionary).CreateDbOpening(m_mepData, ref lstDbOpening))
				{
					result = false;
				}
				else if (!new DbBeamOpeningCreatorFactory(ref lstDoc, this._hWndRevit, dictionary).CreateDbOpening(m_mepData, ref lstDbOpening))
				{
					result = false;
				}
				else if (!new DbEquipWallOpeningCreatorFactory(ref lstDoc, this._hWndRevit, dictionary).CreateDbOpening(m_mepData, ref lstDbOpening))
				{
					result = false;
				}
				else
				{
					result = true;
				}
			}
			catch (Exception ex)
			{
				ExceptionLog.WriteLog(ex.Message, true);
				result = false;
			}
			return result;
		}

		private bool GetAllMEPCurve(List<Document> lstDoc, ref MEPData mepData)
		{
			bool result;
			try
			{
				foreach (Autodesk.Revit.DB.Document document in lstDoc)
				{
					FilteredElementCollector filteredElementCollector = new FilteredElementCollector(document);
					filteredElementCollector.OfCategory(BuiltInCategory.OST_DuctCurves).WhereElementIsNotElementType();
					foreach (Element element in filteredElementCollector)
					{
						Duct duct = element as Duct;
						foreach (object obj in duct.ConnectorManager.Connectors)
						{
							Connector connector = (Connector)obj;
                            if ((int)connector.ConnectorType == 1 && (int)connector.Shape == 1)
							{
								mepData.m_lstDuct.Add(duct);
								break;
							}
						}
					}
				}
				foreach (Autodesk.Revit.DB.Document document2 in lstDoc)
				{
					FilteredElementCollector filteredElementCollector2 = new FilteredElementCollector(document2);
					filteredElementCollector2.OfCategory(BuiltInCategory.OST_CableTray).WhereElementIsNotElementType();
					foreach (Element element2 in filteredElementCollector2)
					{
						mepData.m_lstCableTray.Add(element2 as CableTray);
					}
				}
				foreach (Autodesk.Revit.DB.Document document3 in lstDoc)
				{
					FilteredElementCollector filteredElementCollector3 = new FilteredElementCollector(document3);
					filteredElementCollector3.OfCategory(BuiltInCategory.OST_PipeCurves).WhereElementIsNotElementType();
					foreach (Element element3 in filteredElementCollector3)
					{
						mepData.m_lstPipe.Add(element3 as Pipe);
					}
				}
				foreach (Autodesk.Revit.DB.Document document4 in lstDoc)
				{
					FilteredElementCollector filteredElementCollector4 = new FilteredElementCollector(document4);
					filteredElementCollector4.OfCategory(BuiltInCategory.OST_GenericModel).WhereElementIsNotElementType();
					foreach (Element element4 in filteredElementCollector4)
					{
						FamilyInstance item = element4 as FamilyInstance;
						mepData.m_lstMass.Add(item);
					}
				}
				result = true;
			}
			catch (Exception ex)
			{
				ExceptionLog.WriteLog(ex.Message, true);
				result = false;
			}
			return result;
		}

		public WindowHandle _hWndRevit;
	}
}
